grammar Calc;

@lexer::member{
    public static final int COMMENTS = 1;
}
s : EOF;  

program
	:	program_head program_body DOT           #programStart
	;

program_head
	:	PROGRAM ID LEFT_BRA identifier_list RIGHT_BRA SEMICOLON         #programHead
	;

program_body
	:	const_declarations? type_declarations? var_declarations? subprogram_declarations? compound_statement    #programBody
	;

identifier_list
	:	identifier_list COMMA ID                                #multiIdentifier
	|	ID                                                      #sigIdentifier
	;

// null may
const_declarations
	:	CONST const_declaration SEMICOLON                       #constDecla
	;

const_declaration
	:	const_declaration SEMICOLON ID EQUAL const_variable     #multiConstExt
	|	ID EQUAL const_variable                                 #sigConstExt
	;

const_variable
	:	ADD ID                      #addID
	|	SUB ID                      #subID
	|	ID                          #sigID
	|	ADD NUM                     #addNum
	|	SUB NUM                     #subNum
	|	NUM                         #sigNum
	|	SIGLETTER                   #sigLetter
	;

// null may
type_declarations
	:	TYPE type_declaration SEMICOLON                                 #typeDecla
	;

type_declaration
	:	type_declaration SEMICOLON ID EQUAL type                        #multiType
	|	ID EQUAL type                                                   #sigType
	;

type
	:	standard_type                                                   #baseTypeExt
	|	RECORD record_body? END                                         #recordExt
	|	ARRAY LEFT_BRACKET periods RIGHT_BRACKET OF type                #periodExt
	|   ID                                                              #definedRecord
	;

standard_type
	:	INTEGER|REAL|BOOLEAN|CHAR                                       #baseType
	;

// null may
record_body
	:	var_declaration                                                 #recordBody
	;

periods
	:	periods COMMA period                                            #getPeriodList
	|	period                                                          #getSigPeriod
	;

period
	:	const_variable DOUBLE_DOT const_variable                        #getPeriod
	;

// null may
var_declarations
	:	VAR var_declaration                                   #varDecla
	;

var_declaration
	:	var_declaration identifier_list COLON type SEMICOLON           #getVarDeclaList
	|	identifier_list COLON type SEMICOLON                           #getSigVarDecla
	;

subprogram_declarations
	:	subprogram_declarations subprogram_declaration SEMICOLON        #getSubProDeclaList
	|	subprogram_declaration SEMICOLON                                #getSigSubProDecla
	;

subprogram_declaration
	:	subprogram_head program_body                                    #subProgramDecla
	;

subprogram_head
	:	FUNCTION ID formal_parameter? COLON standard_type SEMICOLON     #funcSubProgram
	|	PROCEDURE ID formal_parameter? SEMICOLON                        #proSubProgram
	;
	
//null may
formal_parameter
	:	LEFT_BRA parameter_lists RIGHT_BRA                          #formalPara
	;

parameter_lists
	:	parameter_lists SEMICOLON parameter_list                    #getParaLists
	|	parameter_list                                              #getSigParaList
	;

parameter_list
	:	var_parameter                                               #paraVar
	|   value_parameter                                             #paraValue
	;

var_parameter
	:	VAR value_parameter                                         #varPara
	;

value_parameter
	:	identifier_list COLON standard_type                         #valueParaAssign
	;

compound_statement
	:	BEGIN statement_list END                                    #getComStatementList
	|	BEGIN END                                                   #nullStatement
	;

//null may
statement_list
	:	statement_list statement SEMICOLON                         #getStatementList
	|	statement SEMICOLON                                        #getSigStatement
	;

//单个语句，不含分号的
statement
	:	variable ASSIGNOP expression                                #assignStatement
	|	call_procedure_statement                                    #proCallStatement
	|	compound_statement                                          #comStatement
	|   write                                                       #writeStatement
	|   read                                                        #readStatement
	|	IF expression THEN statement else_part?                     #ifStatement
	|	CASE expression OF case_body END                            #caseStatement
	|	WHILE expression DO statement                               #whileStatement
	|	REPEAT statement_list UNTIL expression                      #repeatStatement
	|	FOR ID ASSIGNOP expression updown expression DO statement   #forStatement
	;

variable
	:	ID id_varparts                                      #getIDVarPartList
	|   ID                                                  #getSigID
	;

//null may
id_varparts
	:	id_varparts id_varpart                              #getIDVarList
	|	id_varpart                                          #getSigIDVar
	;

id_varpart
	:	LEFT_BRACKET expression_list RIGHT_BRACKET          #expID
	|	DOT ID                                              #fieldID
	;

// null may
else_part
	:	ELSE statement                                      #elsePart
	;
	
//CASE 分支
case_body
	:	branch_list?                                        #getBranchBody
	;

//分支列表
branch_list
	:	branch_list  branch SEMICOLON                       #getBranchList
	|	branch SEMICOLON                                    #getSigBranch
	;

//单个分支
branch
	:	const_list COLON statement                          #sigBranch
	;

//用,分开的
const_list
	:	const_list COMMA const_variable                     #getConstList
	|	const_variable                                      #getSigConst
	;

updown
	:	TO|DOWNTO                                           #getDir
	;

//过程调用
call_procedure_statement
	:	ID                                                  #getPro
	|	ID LEFT_BRA expression_list RIGHT_BRA               #getFunc
	;

//表达式列表，用‘,’分开
expression_list
	:	expression_list COMMA expression                    #getExpList
	|	expression                                          #getSigExp
	;

//表达式
expression
	:	simple_expression (EQUAL|RELOP) simple_expression   #relopSimExp
	|	simple_expression                                   #sigSimExp
	;

//简单表达式，只包含计算符
simple_expression
    :   simple_expression (OR|ADD|SUB) term     #simTerm
	|	term                                    #sigTerm
	|   ADD term                                #addTerm
	|	SUB term                                #subTerm
	;
//项
term
	:	term MULOP factor                       #multiFactor
	|	factor                                  #sigFactor
	;
//因子
factor
	:	unsign_const_variable                       #ucvFactor
	|   variable                                    #varFactor
	|   ID LEFT_BRA expression_list RIGHT_BRA       #funcFactor
	|	LEFT_BRA expression RIGHT_BRA               #expFactor
	|	NOT factor                                  #notFactor
	;

unsign_const_variable
	:	ID                                           #unsignConstVariableID
	|	NUM                                          #unsignConstVariableNum
	|	SIGLETTER                                    #unsignConstVariableLetter
	|   booleanEnum                                  #unsignConstVariableBoolean
	;

read
    :   READ LEFT_BRA para_table_read RIGHT_BRA      #readSomePara
    ;

write
    :   WRITE LEFT_BRA para_table_write RIGHT_BRA     #writeSomePara
    ;

para_table_read
    :   ID COMMA para_table_read                        #readParaTable
    |   ID                                              #readPara
    ;

para_table_write
    :   (ID|SIG_STRING) COMMA para_table_write #getWriteParaTable
    |   ID                                                   #getWritePara
    |   SIG_STRING                                #getWriteString
    ;

booleanEnum
    :   TRUE|FALSE                              #getBoolean
    ;



NOTE_MUL
	:	'(*' .+? '*)'  ->channel(HIDDEN)
	;

NOTE_SIG
	:	'{' .+? '}'    ->channel(HIDDEN)
	;

ADD
    :   '+'
    ;

SUB
    :   '-'
    ;


MULOP
	:	'*'
	|   '/'
	|   DIV
	|   MOD
	|   AND
	;

//punctuation
SIG_QUT:'\'';
LEFT_BRA:'(';
RIGHT_BRA:')';
LEFT_BRACKET:'[';
RIGHT_BRACKET:']';
COMMA:',';
COLON:':';
DOT:'.';
DOUBLE_DOT:'..';
SEMICOLON:';';
EQUAL:'=';
//end



//key word start

TRUE
    :   'true'
    ;

FALSE
    :   'false'
    ;

READ
    :   'read'
    ;

WRITE
    :   'write'
    ;

AND
	:	'and'
	;
	
ARRAY
	:	'array'
	;

BEGIN
	:	'begin'
	;
	
BOOLEAN
	:	'boolean'
	;
	
CASE
	:	'case'
	;

CONST
	:	'const'
	;

DIV
	:	'div'
	;

DO
	:	'do'
	;
	
DOWNTO
	:	'downto'
	;

ELSE
	:	'else'
	;

END
	:	'end'
	;

FOR
	:	'for'
	;

FUNCTION
	:	'function'
	;

IF
	:	'if'
	;

INTEGER
	:	'integer'
	;

MOD
	:	'mod'
	;

NOT
	:	'not'
	;

OF
	:	'of'
	;

OR
	:	'or'
	;

PROCEDURE
	:	'procedure'
	;

PROGRAM
	:	'program'
	;

REAL
	:	'real'
	;

RECORD
	:	'record'
	;

REPEAT
	:	'repeat'
	;

THEN
	:	'then'
	;

TO
	:	'to'
	;

TYPE
	:	'type'
	;

UNTIL
	:	'until'
	;
	
VAR
	:	'var'
	;
	
WHILE
	:	'while'
	;
	
CHAR
	:	'char'
	;
	
//key word end

SIGLETTER
    :   SIG_QUT LETTER SIG_QUT
    ;

ID
    :   LETTER(DIGIT|LETTER)*
    ;

NUM
	:	(DIGITS|FRACTION) ( 'E' ('+'|'-')? DIGITS)?
	;

LETTER
	:	[a-zA-Z]
	;

DIGIT
	: 	[0-9]
	;

DIGITS
	: 	DIGIT+
	;

FRACTION
	:	DIGITS '.' DIGITS
	;

RELOP
	:	'<='
	|   '>='
	|   '<>'
	|   '<'
	|   '>'
	|   EQUAL
	;

ASSIGNOP
	:	':='
	;

SIG_STRING: '\'' ('\\\''|~['])* '\'' ;

WS
    : 	[ \r\n\t]+ -> skip
    ;